package client;

import lovedna.task.DelayCall;
import lovedna.game.GameMain;
import lovedna.LoveDNA;
import lovedna.ISystem;
import lovedna.game.components.Light;
import lovedna.game.components.Camera;
import lovedna.game.World;
import lovedna.utils.Mathf;
import lovedna.Time;
import lovedna.math.Vector3;
import lovedna.game.events.ActorEvent;
import lovedna.game.components.Component;
import lovedna.graphics.CullMode;
import lovedna.game.materials.Material;
import lovedna.game.rendering.SortingCriteria;
import lovedna.game.rendering.DrawingSettings;
import lovedna.game.rendering.FilteringSettings;
import lovedna.game.rendering.RenderEvent;
import lovedna.game.rendering.RenderContext;
import lovedna.game.rendering.RenderingData;
import lovedna.game.rendering.RenderPass;
import lovedna.game.components.Gltf;
import lovedna.game.helper.DebugRender;
import lovedna.Debug;
import lovedna.game.materials.RenderQueue;
import lovedna.game.helper.DebugFrame;
import lovedna.game.components.MeshRenderer;
import lovedna.game.Mesh;
import lovedna.math.Vector4;
import lovedna.ds.BufferVector4;
import lovedna.game.geometry.GeomCylinder;
import lovedna.utils.macro.CompileTime;
import lovedna.game.materials.ShaderSource;
import lovedna.game.Actor;
import lovedna.resource.R;

/**
 * ... 
 * @author liwei
 */
class Client extends GameMain {
	public static function main():Void {
		lovedna.utils.macro.CompileTime.buildNumberToFile("assets/html5/version.js", "version=0x{0};");
		LoveDNA.watch("web.renderCanvas", () -> {
			new Client();
		});
	}

	public function new() {
		super();
		R.init("assets");
		doGameInit();
		// var system:ISystem = cast LoveDNA.getParam("system");
		// if (system != null) {
		// 	system.setInteractCallback(doGameInit);
		// } else {
		// 	doGameInit();
		// }
	}

	function doGameInit() {
		var jsinit:Void->Void = cast LoveDNA.getParam("init");
		if (jsinit != null) {
			DelayCall.add(new DelayCall(()->{
				jsinit();
			trace("jsinit");
			}),0.3);
			
		}
		// Debug.editorMode = true;
		trace("gameinit ", LoveDNA.getParam("version"));
		R.setVersion("version.bin", LoveDNA.getParam("version"));
		R.loadMeta("version.bin", start);

		new ShaderSource("instance", CompileTime.readFile("resource/shaders/instance.glsl"));
		new ShaderSource("animal", CompileTime.readFile("resource/shaders/animal.glsl"));

		// var actor = new Actor();
		// _world.addChild(actor);
		// actor.addComponent(AxisLine);
		// actor.addComponent(GridLine);

		// _camera.actor.addComponentIfNotExist(CameraControl);
		// cc.clampX.set(0, 360);
		// cc.scaleRotationX=0;
		// cc.distance = 18;
		// cc.scaleRotationY = 1;
		// cc.zoomDelta = 0.002;

		new DebugFrame(_game);
		DebugRender.DepthMode = true;
		this._light.actor.addComponent(Move);
	}

	private function start() {
		F.init();
		F.table.init(R.table.getRes("data/data.bin"), metaSuccess);

		// return;

		var actor = new Actor();
		actor.transform.position.y = 0.6;
		var buffers:GeomCylinder = new GeomCylinder();
		buffers.radiusBottom = 0.1;
		buffers.radiusTop = 0.02;
		buffers.radiusSegments = 8;
		buffers.height = 0.6;
		buffers.color2 = new BufferVector4();
		buffers.color2.instanceDivisor = 1;
		var c = new Vector4();
		var s = 20;
		var count = 10000;
		for (i in 0...count) {
			var r = Math.random() * 360;
			var d = Math.random() * s + Math.random() * 3;
			var x = Math.cos(r) * d;
			var z = Math.sin(r) * d;
			c.set(x, -Math.random() * 1, z, Math.random());
			buffers.color2.push(c);
		}
		var mesh:Mesh = new Mesh();
		mesh.fromBuffer(buffers.build());
		buffers.update();
		mesh.gpuBuffer.indexBuffer.instancedCount = count;
		var r = actor.addComponent(MeshRenderer);
		r.material.renderQueue = RenderQueue.Transparent;
		r.material.loadShader("instance");
		r.cameraCull = false;
		r.mesh = mesh;
		_world.addChild(actor);
	}

	private function metaSuccess() {
		var stage:Stage = new Stage(_camera);
		_world.addChild(stage);
		stage.load(1);
		_world.renderPipeline.addFeaturePass(new OutLinePass());
	}
	/*======get set methods======================*/
}

class OutLinePass extends RenderPass {
	private var _filteringSetting:FilteringSettings;
	private var _drawingSetting:DrawingSettings;
	private var _outlineMat:Material;

	public function new() {
		super(RenderEvent.opaques + 1);
		_filteringSetting = new FilteringSettings();
		_filteringSetting.layerMask = 1 << 10;
		_drawingSetting = new DrawingSettings();
		_drawingSetting.tag = "outline";
		_drawingSetting.sort = SortingCriteria.opaque;
		new ShaderSource("outline", CompileTime.readFile("resource/shaders/outline.glsl"));
		_outlineMat = new Material("outline");
		_outlineMat.renderState.cullMode = CullMode.front;
		_outlineMat.renderState.depthState.setDepthTest(true);

		_outlineMat.renderState.offsetFactor = 5;
		_outlineMat.renderState.offsetUnits = 1;
		_outlineMat.color.set(0, 1, 0, 0.1);
		_outlineMat.setColor("gcolor", _outlineMat.color);
		_drawingSetting.overrideMaterial = _outlineMat;
	}

	override function execute(context:RenderContext, renderingData:RenderingData) {
		renderingData.filter(this._filteringSetting);
		renderingData.draw(context, _drawingSetting);
	}
}

class Move extends Component {
	private var time:Float;

	override function onStart() {
		super.onStart();
		time = 0;
		bindEvent(ActorEvent.onUpdate, OnUpdate);
	}

	private function OnUpdate(?e) {
		time += actor.deltaTime;
		var sin = Math.sin(time);
		var cos = Math.cos(time);
		actor.transform.position.set(sin, 5, cos);
		actor.transform.rotation.lookAt(actor.transform.position, Vector3.zero);
	}
}
